/*
 * newClient.c
 *
 *  Created on: Nov 23, 2009
 *      Author: user
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sys/un.h>
#include <arpa/inet.h>

#define ARRAY_SIZE (1000)   /*this is the number of processes*/
#define STRING_SIZE (1000) /*this is the max size of the cmdline of a process*/
#define DGRAM_BUFSIZE 50000
/**
 * Adds the string that starts in address b, to the buffer that starts in string
 * in position *string_len
 * */
char *addStringToBuffer(char *string, const char *b, int *string_len) {
    strcpy(&string[*string_len], b);
    (*string_len) += strlen(b);
    if (*string_len > DGRAM_BUFSIZE)
        perror("buffer exceeded DATAGRAM BUFSIZE! Exiting..\n");
    return string;
}

/**
 * Adds the int b to the string in place *retbuflen, and forwards *retbuflen
 * by 4 (sizeof(int)).
 * */
char *addIntToBuffer(char *string, int b, int *retbuflen) {
    int i;
    for (i=0; i<4; i++)
        string[(*retbuflen)+i] = *(((char*)&b)+i);
    *retbuflen += 4;
    if (*retbuflen > DGRAM_BUFSIZE)
        perror("buffer exceeded DATAGRAM BUFSIZE! Exiting..\n");
    return string;
}


char* get_packet_to_send(int num_of_processes , char process_names[ARRAY_SIZE][STRING_SIZE], char *packet){
    int bufpos=0;
    int i,tmp=0;
    printf("num of processes: %d\n", num_of_processes);
    addIntToBuffer(packet , num_of_processes, &bufpos);
    for (i=0; i<num_of_processes; i++) {
        tmp = strlen(process_names[i]);
        addIntToBuffer(packet, tmp, &bufpos);
        addStringToBuffer(packet, process_names[i], &bufpos);
    }

    return packet;
}


int is_digit(char a){
    if( a>47 && a<58) {
        return 1;
    }
    return 0;
    }

int is_process(char* str){
    int booli = 1;
    int i;
    for(i = 0; i< strlen(str); i++){
        if(!is_digit(str[i])){
            booli = 0;
        }
    }

    return booli;

}
/*this gets a 2 dimensional array and fills it with the processes cmdlines.*/
int get_processes_array(char processes_array[ARRAY_SIZE][STRING_SIZE] , int* num_of_processes) {
   int counter = 0;
   DIR *dir = NULL;
   FILE *cmd_content_file;
   struct dirent *dir_enteries = NULL;
   char cmdline_path[30] = "";
   char cmd_content_buffer[STRING_SIZE] = "";



 if ((dir = opendir("/proc")) == NULL) {
     perror("error opening dir");
       return -1;
   }

    /* we loop over all the dir /proc sub directories , if it is a process , we want to add its cmdline to our array*/
    while ((dir_enteries = readdir(dir)) != NULL) {
    /*if dir's subdir is not a process than continue*/
       if (!is_process(dir_enteries->d_name)){

           continue;
       }
    /*if it is a process , make the path to retrieve the cmdline of this process*/
       strcpy(cmdline_path, "/proc/");
       strcat(cmdline_path, dir_enteries->d_name);
       strcat(cmdline_path, "/cmdline");
    /*open the file of this path containing the cmdline data*/
       if ((cmd_content_file = fopen(cmdline_path, "r")) == NULL) {
           perror("error opening file");
           return -1;
       }
          /*scan the first string in the cmdline and copy it to processes array in counter position*/
    cmd_content_buffer[0]='\0';/*this is so it wont repeat processes , if the cmdline is empty it the fscanf will not do anything , so still we want to change the cmd_content_buffer to '\0'*/

    fscanf(cmd_content_file,"%s", cmd_content_buffer);

    /*finally we copy the content of our buffer to the array of processes*/
    strcpy(processes_array[counter], cmd_content_buffer);
        counter++;

       fclose(cmd_content_file);
   }
    /*we add at the end of the processes array the sign $ so we'll know , we have ended to read processes*/
    processes_array[counter][0] = '$';
   if (closedir (dir) != 0) {
      perror("error closing dir");
       return -1;
   }
    *num_of_processes = counter - 1;
    return 0;
}
/**
 * This function is used to handle errors - currently it prints out
 * the error message and then exits with an error code (-1)
 * */
void handle_error(char* s) {
    printf("Error: %s\n", s);
    exit(-1);
}

/**
 * This function handles the arguments passed to the program - fills the
 * struct sockaddr_in according to them.
 * */

void inArguments(int family,int PORT,struct sockaddr_in *serverAddr){
	serverAddr->sin_family=family;
	serverAddr->sin_port=htons(PORT);
	serverAddr->sin_addr.s_addr=inet_addr("132.67.105.220");
	memset(serverAddr->sin_zero,'\0',sizeof(serverAddr->sin_zero));
    return;
}

void unArguments(int family,struct sockaddr_un *serverAddr,const char* sock_path){
	(*serverAddr).sun_family = family;
	strcpy((*serverAddr).sun_path,sock_path); //how do I get the SOCK_PATH
    return;
}


void mysend(int protocol,int sockfd,void* list,int len,struct sockaddr *serverAddr){
	int er;
	if(protocol == SOCK_STREAM){
		if(-1 == send(sockfd,list,len,0))
			{
				handle_error("Error at sending\n");
			}
	}else{
		if(protocol == SOCK_DGRAM){
			/*pad to 50k bytes*/

			if(-1 == sendto(sockfd,list,1000,0,serverAddr,sizeof(struct sockaddr))){
				handle_error("Error at sending\n");
			}
		}
	}
}

int inet_streamClient(int PORT,char* data){
	struct sockaddr_in serverAddr;
	int sockfd;

	/*calibrating server info */
	inArguments(PF_INET,PORT,&serverAddr);

	/*let's create a socket */
	sockfd = socket(serverAddr.sin_family,SOCK_STREAM,0); //what's 0 for protocol

	/* let's connect */
	if(-1 == connect(sockfd,(struct sockaddr *) &serverAddr, sizeof(serverAddr)))
		handle_error("Error at sending\n");

	/* let's send shit*/
	/* get Data from paskar */
	mysend(SOCK_STREAM,sockfd,data,50000,&serverAddr);

	close(sockfd);

}

int inet_dgramClient(int PORT,char* data){
	struct sockaddr_in serverAddr;
	int sockfd;

	/*calibrating server info */
	inArguments(PF_INET,PORT,&serverAddr);

	/*let's create a socket */
	sockfd = socket(serverAddr.sin_family,SOCK_DGRAM,0); //what's 0 for protocol

	/* let's send shit*/
	/* get Data from paskar */
	printf("sending....");
	mysend(SOCK_DGRAM,sockfd,data,50000,&serverAddr);

	close(sockfd);
}

int unix_streamClient(int PORT,char* data){
	struct sockaddr_un serverAddr;
	int sockfd;

	/*calibrating server info */
	unArguments(PF_UNIX,&serverAddr,"/tmp/us");

	/*let's create a socket */
	sockfd = socket(serverAddr.sun_family,SOCK_STREAM,0); //what's 0 for protocol

	/* let's connect */
	if(-1 == connect(sockfd,(struct sockaddr *) &serverAddr, sizeof(serverAddr))) /*len = strlen(remote.sun_path) + sizeof(remote.sun_family);*/
		handle_error("Error at sending\n");

	/* let's send shit*/
	/* get Data from paskar */
	mysend(SOCK_STREAM,sockfd,data,50000,&serverAddr);

	close(sockfd);
}

int unix_dgramClient(int PORT,char* data){
	struct sockaddr_un serverAddr;
	int sockfd;

	/*calibrating server info */
	unArguments(PF_UNIX,&serverAddr,"/tmp/ud");

	/*let's create a socket */
	sockfd = socket(serverAddr.sun_family,SOCK_DGRAM,0); //what's 0 for protocol

	/* let's send shit*/
	/* get Data from paskar */
	mysend(SOCK_DGRAM,sockfd,data,50000,&serverAddr);

	close(sockfd);

}


int main(int argc,char** argv){

	char* SOCK_TYPE = getenv("SOCK_TYPE");
	int PORT = atoi(getenv("PORT"));
	time_t waitUntil = atoi(getenv("TSTART")), now=time(NULL);
	int counter=0;
	char packet[50000];
	char proc_cont[ARRAY_SIZE][STRING_SIZE];


	printf("need to wait for unix time %d it's now %d\n", waitUntil, now);
	if (now < waitUntil)
	{
		int interval = waitUntil - now;
		printf("sleeping for %d seconds\n",interval);
		sleep(interval);
	}
	else printf ("cannot wait for time in the past\n");


	get_processes_array(proc_cont,&counter);
	get_packet_to_send(counter,proc_cont,packet);

	if(strcmp(SOCK_TYPE,"IS")==0)
	/* INET Stream */
		inet_streamClient(PORT,packet);
	if(strcmp(SOCK_TYPE,"ID")==0)
	/* INET Dgram */
		inet_dgramClient(PORT,packet);
	if(strcmp(SOCK_TYPE,"US")==0)
	/* Unix Stream */
		unix_streamClient(PORT,packet);
	if(strcmp(SOCK_TYPE,"UD")==0)
	/* Unix Dgram */
		unix_dgramClient(PORT,packet);

	return 0;
}
